// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/field-type.h"

#include "src/handles-inl.h"
#include "src/objects-inl.h"
#include "src/objects/smi.h"
#include "src/ostreams.h"

namespace v8 {
namespace internal {

    // static
    FieldType FieldType::None() { return FieldType(Smi::FromInt(2).ptr()); }

    // static
    FieldType FieldType::Any() { return FieldType(Smi::FromInt(1).ptr()); }

    // static
    Handle<FieldType> FieldType::None(Isolate* isolate)
    {
        return handle(None(), isolate);
    }

    // static
    Handle<FieldType> FieldType::Any(Isolate* isolate)
    {
        return handle(Any(), isolate);
    }

    // static
    FieldType FieldType::Class(Map map) { return FieldType::cast(map); }

    // static
    Handle<FieldType> FieldType::Class(Handle<Map> map, Isolate* isolate)
    {
        return handle(Class(*map), isolate);
    }

    // static
    FieldType FieldType::cast(Object object)
    {
        DCHECK(object == None() || object == Any() || object->IsMap());
        return FieldType(object->ptr());
    }

    bool FieldType::IsClass() const { return this->IsMap(); }

    Map FieldType::AsClass() const
    {
        DCHECK(IsClass());
        return Map::cast(*this);
    }

    bool FieldType::NowStable() const
    {
        return !this->IsClass() || AsClass()->is_stable();
    }

    bool FieldType::NowIs(FieldType other) const
    {
        if (other->IsAny())
            return true;
        if (IsNone())
            return true;
        if (other->IsNone())
            return false;
        if (IsAny())
            return false;
        DCHECK(IsClass());
        DCHECK(other->IsClass());
        return *this == other;
    }

    bool FieldType::NowIs(Handle<FieldType> other) const { return NowIs(*other); }

    void FieldType::PrintTo(std::ostream& os) const
    {
        if (IsAny()) {
            os << "Any";
        } else if (IsNone()) {
            os << "None";
        } else {
            DCHECK(IsClass());
            os << "Class(" << reinterpret_cast<void*>(AsClass()->ptr()) << ")";
        }
    }

    bool FieldType::NowContains(Object value) const
    {
        if (*this == Any())
            return true;
        if (*this == None())
            return false;
        if (!value->IsHeapObject())
            return false;
        return HeapObject::cast(value)->map() == Map::cast(*this);
    }

} // namespace internal
} // namespace v8
